#include "GLState.h"
#include "platform/PlatUtil.h"

GLuint GLState::s_darkBg = 0;
GLuint GLState::s_lightBg = 0;

void GLState::genBgTexture(bool isDarkMode, GLuint texUnit) {
	std::string imgPath;
	if (isDarkMode)
		imgPath = Config::View3D_BgDarkImgPath;
	else
		imgPath = Config::View3D_BgLightImgPath;
	CByteArray compressedImgBytes;
	PlatUtil::readFileAsBytes(compressedImgBytes, imgPath);

	auto img = CImage(compressedImgBytes.data(), compressedImgBytes.size());
	img.invertY().crop((img.width() - W3D) / 2, img.height() - H3D, W3D, H3D);

	auto bgTexture = loadTexture(img, texUnit);
	if (isDarkMode) s_darkBg = bgTexture;
	else s_lightBg = bgTexture;

	waitToFinish();
}

/**
 * @warning The OpenGL specification specifies that the alignment value must be a power of 2 and not exceed 8.
 * @note The default GL-UNPACK ALIGNMENT for OpenGL is 4, which means that the number of bytes per line needs to be aligned to 4 bytes.
		 For the GL_RGB format (3 bytes per pixel), if width * 3 is not a multiple of 4, the alignment needs to be manually adjusted.
		 Otherwise, `glTexImage2D` may lead to GL_INVALID_VALUE or Segment-Fault!
		 Can use `glPixelStorei(GL_UNPACK_ALIGNMENT, 1);` to lift restrictions.
 * @link https://registry.khronos.org/OpenGL-Refpages/es3/html/glPixelStorei.xhtml
 */
GLuint GLState::loadTexture(const CImage& textureImg, GLuint texUnit) {
	GLuint texture;
	glGenTextures(1, &texture);
	glActiveTexture(GL_TEXTURE0 + texUnit);
	glBindTexture(GL_TEXTURE_2D, texture);

	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	if (textureImg.isValid()) {
		auto internalFormat = GL_RGB8;
		auto format = GL_RGB;
		if (textureImg.channels() == 4) {
			internalFormat = GL_RGBA8;
			format = GL_RGBA;
		}
		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, textureImg.width(), textureImg.height(), 0, format, GL_UNSIGNED_BYTE, textureImg.data());CHECK_GL_ERR
		//glGenerateMipmap(GL_TEXTURE_2D);
	} else
		EXIT("Failed to load texture");
	return texture;
}

void GLState::saveImageByData(void* pixelData, const std::string& savePath, bool hasAlphaChannel, int cropX, int cropY, int cropW, int cropH, float ssaa) {
	CUtil::doInBgThread([=] {
		const int W3D_SSAA = W3D * ssaa;
		const int H3D_SSAA = H3D * ssaa;
		auto bytes = reinterpret_cast<UChar*>(pixelData);
		auto img = CImage(bytes, W3D_SSAA, H3D_SSAA, hasAlphaChannel ? 4 : 3);
		img.resize(W3D, H3D).invertY().crop(cropX, cropY, cropW, cropH);
		bool success = img.save(savePath);

		ASSERT(success, "stbi_write_png/jpg fail!");
	});
}